/*	 
**	 Solution to Calculator exercise, lab #1.
**	 Authors: Bruce Blumberg and Doug Keislar, NeXT Technical Support
*/


#import "Calculator.h"
#import <string.h>
#import <math.h>	/* for extensions to existing functionality */	
#import <appkit/Application.h>
#import <appkit/TextField.h>

@implementation Calculator

+new;
{	
	self = [super new];	    /* create new instance of calculator */
	strcpy(viewerStr,"");	    /* initialize string for viewer */
	topOfStack = -1;	    /* initialize stack */
	frozen = NO;
	return self;
}

-(double)pop
{
	if(topOfStack>-1)	 
		return(stack[topOfStack--]);
	else {
		[self stackError:"stack underflow"];
		return(0);
	}
}

-push:(double)aNum
{
	if(topOfStack<STACKSIZE-1)
		stack[++topOfStack] = aNum;
	else [self stackError:"stack overflow"];
	return self;
}

-(double)getOperand
{	
	if (frozen)
		return (0.0);
        if (viewerStr[0]) 
		[self enter:self];	/* push displayed value to stack,
					if it hasn't already been done */
	return ([self pop]);
}

-displayValue:(double)aNum
{
	if (frozen)
		return self;
	[viewer setFloatValue:aNum]; 	/* display current value */
	strcpy(viewerStr,"");		/* and empty out string for next */
	return self;
}

-pushAndDisplay:(double)aNum
{
	if (frozen)
		return self;
	[self push:aNum];
	[self displayValue:aNum];
	return self;
}

-enter:(id)sender
{	
	if (frozen)
		return self;
	[self push:[viewer floatValue]];
	strcpy(viewerStr,"");		
	return self;
}

-clearDisplay:(id)sender
{
	if (frozen)  
		frozen = NO;	     
	strcpy(viewerStr,"");
	[self displayValue:0.0];
	return self;
}

-digit:(id)sender
{
	char	digitBuf[2];
	
	if (frozen)
		return self;
			/* get the new digit from the  button's tag and 
			  append it to the displayed string */
	sprintf(digitBuf,"%d",[sender selectedTag]);  
			/* we use selectedTag instead of tag, in case the
			button is part of a matrix */	
	strcat(viewerStr,digitBuf);	      
	[viewer setStringValue:viewerStr];
	return self;
}
	
-period:(id)sender
{
	if (!frozen)	{	
		strcat(viewerStr,".");
		[viewer setStringValue:viewerStr];
	}
	return self;
}
	
-add:(id)sender
{	

	if (!frozen) 
		[self pushAndDisplay:[self getOperand] + [self getOperand]];
	return self;
}

-subtract:(id)sender
{
	if (!frozen)		
		[self pushAndDisplay:-[self getOperand] + [self getOperand]];
	return self;
}

-multiply:(id)sender
{
	if (!frozen)		
		[self pushAndDisplay:[self getOperand] * [self getOperand]];
	return self;
}

-divide:(id)sender
{	
	double firstOp;
	
	if (!frozen)
	{		
		firstOp = [self getOperand];
		[self pushAndDisplay:[self getOperand]/firstOp];
	}
	return self;
}

-changeSign:(id)sender		/* we don't  push to stack here, so digits
				 can be appended after sign is changed */
{
	if (!frozen)
	{
		[viewer setFloatValue:(-[viewer floatValue])];
		strcpy (viewerStr,[viewer stringValue]);
	}
	return self;
}

-stackError:(STR)errorMsg;
{
	[viewer setStringValue:errorMsg];
	frozen = YES;
	topOfStack = -1;  	   /* stack errors re-initialize stack */
	return self;
}


- setAWindow:anObject		/* associate the outlet "aWindow" with
				   the user-interface window, "anObject"  */
{
 	 aWindow = anObject;
  	 [aWindow setDelegate:self];	  /* needed for windowWillClose: */
  	 return self;
}

- setViewer:anObject		/*  initialize the other outlet, viewer  */
{
	  viewer = anObject;
	  return self;
}

- windowWillClose:sender 	/* needed only if calculator has a close
		       button that will be used for quitting the application,
		       as a supplement to the "Quit" menu item. This is
		       not recommended; normally only the "Quit" menu
		       item should cause an application to quit. */
{
	[NXApp terminate:self];
	return self;
}
	
@end

